package com.zkteco.biometric;

import android.content.Context;
import android.hardware.usb.UsbConstants;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbEndpoint;
import android.hardware.usb.UsbInterface;
import android.hardware.usb.UsbManager;
import android.text.TextUtils;
import android.util.Log;

import java.util.HashMap;
import java.util.Iterator;

public class EKTPUSBConnectionHost {
    private UsbDeviceConnection mConnection = null;
    
    private int mVendorID = 0;
    private int mProductID = 0;
    private int mFd = 0;
    private int mBusNum = 0;
    private int mDevAddr = 0;
    private int mInEndPointAddr = 0;
    private int mOutEndPointAddr = 0;
    private final int TYPE_USB = 0;
    private String mDeviceName = "";
    private static final int INTERFACE_SUBCLASS = 6;
    private static final int INTERFACE_PROTOCOL = 80;

    class InnerUSBInterface
    {
        public UsbInterface mUsbInterface = null;
        public UsbEndpoint mInEndpoint = null;
        public UsbEndpoint mOutEndpoint = null;
    };
    private InnerUSBInterface mUsbInterfaces[] = null;
    private int mInterfaceCount = 0;

    public int getVendorID()
    {
        return this.mVendorID;
    }

    public int getProductID()
    {
        return this.mProductID;
    }

    public int getFD()
    {
        return this.mFd;
    }

    public int getBusNum()
    {
        return this.mFd;
    }

    public int getDevAddr()
    {
        return this.mDevAddr;
    }

    public int control(int requestType, int request, int value, int index, byte[] buffer, int length, int timeout) {
        int ret = mConnection.controlTransfer(requestType, request, value, index, buffer, length, timeout);
        return ret;
    }


    public int read(final int index, final byte[] buffer, final int length, final int timeout) {
        if (null == mUsbInterfaces)
        {
            return -1;
        }
        int ret =  mConnection.bulkTransfer(mUsbInterfaces[index].mInEndpoint, buffer, length, timeout);
        return ret;
    }

    public int write(final int index, final byte[] buffer, final int length, final int timeout) {
        if (null == mUsbInterfaces)
        {
            return -1;
        }
        int ret =  mConnection.bulkTransfer(mUsbInterfaces[index].mOutEndpoint, buffer, length, timeout);
        return ret;
    }

    public int getInterfaceCount()
    {
        return mInterfaceCount;
    }

    public int startApdu(final int index)
    {
        if (null == mUsbInterfaces)
        {
            return -1;
        }
        mConnection.claimInterface(mUsbInterfaces[index].mUsbInterface, true);
        return 0;
    }

    public int stopApdu(final int index)
    {
        if (null == mUsbInterfaces)
        {
            return -1;
        }
        mConnection.releaseInterface(mUsbInterfaces[index].mUsbInterface);
        return 0;
    }

    public int getTransportType()
    {
        return TYPE_USB;
    }

    
    protected boolean usb_endpoint_dir_out(UsbEndpoint ep) {
        final int USB_ENDPOINT_DIR_MASK = 0x80;
        final int USB_DIR_OUT = 0x00;
        return (ep.getAddress() & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT;
    }

    protected boolean usb_endpoint_dir_in(UsbEndpoint ep) {
        final int USB_ENDPOINT_DIR_MASK = 0x80;
        final int USB_DIR_IN = 0x80;
        return (ep.getAddress() & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN;
    }

    protected boolean usb_endpoint_xfer_bulk(UsbEndpoint ep) {
        final int USB_ENDPOINT_XFERTYPE_MASK = 0x03;
        final int USB_ENDPOINT_XFER_BULK = 0x02;
        return (ep.getAttributes() & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK;
    }


    public boolean openDevice(Context context, int vid, int pid, int index)
    {
        if (null == mUsbInterfaces)
        {
            mUsbInterfaces = new InnerUSBInterface[16];
            for (int i=0;i<16;i++)
            {
                mUsbInterfaces[i] = new InnerUSBInterface();
            }
        }
        int nCurIndex = 0;
        mInterfaceCount = 0;
        UsbDevice curDevice = null;
        UsbManager usbManager = (UsbManager)context.getSystemService(Context.USB_SERVICE);
        HashMap<String, UsbDevice> deviceList = usbManager.getDeviceList();
        Iterator<UsbDevice> deviceIterator = deviceList.values().iterator();
        while(deviceIterator.hasNext()){
            UsbDevice device = deviceIterator.next();
            if((device.getVendorId()==vid)&&(device.getProductId()==pid)){
                if (nCurIndex++ == index)
                {
                    int interfaceCount = device.getInterfaceCount();
                    for (int i = 0; i < interfaceCount; i++) {
                        UsbInterface usbInterface = device.getInterface(i);
                        if (usbInterface.getInterfaceClass() != UsbConstants.USB_CLASS_CSCID) {
                            continue;
                        }
                        for (int j = 0; j < usbInterface.getEndpointCount(); j++) {
                            UsbEndpoint endpoint = usbInterface.getEndpoint(j);
                            if (usb_endpoint_xfer_bulk(endpoint)) {
                                if (usb_endpoint_dir_in(endpoint)) {
                                    mUsbInterfaces[mInterfaceCount].mInEndpoint = endpoint;
                                } else if (usb_endpoint_dir_out(endpoint)) {
                                    mUsbInterfaces[mInterfaceCount].mOutEndpoint = endpoint;
                                }
                            }
                        }
                        mUsbInterfaces[mInterfaceCount].mUsbInterface = usbInterface;
                            mInterfaceCount++;
                    }
                    if (mInterfaceCount > 2)
                    {
                        curDevice = device;
                    }
                }
            }
        }
        if (null == curDevice)
        {
            return false;
        }
        mConnection = usbManager.openDevice(curDevice);
        if (null == mConnection)
        {
            return false;
        }
        this.mVendorID = curDevice.getVendorId();
        this.mProductID = curDevice.getProductId();
        mFd = mConnection.getFileDescriptor();
        mDeviceName = curDevice.getDeviceName();
        final String[] v = !TextUtils.isEmpty(mDeviceName) ? mDeviceName.split("/") : null;
        if (v != null && v.length >= 2) {
            mBusNum = Integer.parseInt(v[v.length-2]);
            mDevAddr = Integer.parseInt(v[v.length-1]);
        }
        return true;
    }

    public boolean closeDevice()
    {
        if (null != mConnection)
        {
            mConnection.close();
        }
        mConnection = null;
        return true;
    }
}

